package com.newfiber.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.newfiber.common.core.enums.EBoolean;
import com.newfiber.common.core.exception.ServiceException;
import com.newfiber.common.core.web.domain.BaseEntity;
import com.newfiber.common.core.web.service.BaseServiceImpl;
import com.newfiber.common.security.utils.SecurityUtils;
import com.newfiber.system.api.domain.SysRole;
import com.newfiber.system.api.domain.SysUser;
import com.newfiber.system.domain.AppMenu;
import com.newfiber.system.domain.AppRoleMenu;
import com.newfiber.system.domain.request.appMenu.AppMenuQueryRequest;
import com.newfiber.system.domain.request.appMenu.AppMenuSaveRequest;
import com.newfiber.system.domain.request.appMenu.AppMenuUpdateRequest;
import com.newfiber.system.domain.vo.TreeSelect;
import com.newfiber.system.mapper.AppMenuMapper;
import com.newfiber.system.mapper.SysRoleMapper;
import com.newfiber.system.service.IAppMenuService;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * APP菜单Service业务层处理
 * 
 * @author X.K
 * @date 2023-03-20
 */
@Service
public class AppMenuServiceImpl extends BaseServiceImpl<AppMenuMapper, AppMenu> implements IAppMenuService {

    @Resource
    private AppMenuMapper appMenuMapper;

    @Resource
    private SysRoleMapper roleMapper;

    @Resource
    private AppRoleMenuServiceImpl appRoleMenuService;

    @Override
    public long insert(AppMenuSaveRequest request) {
        AppMenu appMenu = new AppMenu();
        BeanUtils.copyProperties(request, appMenu);
        save(appMenu);
        return Optional.of(appMenu).map(BaseEntity::getId).orElse(0L);
    }

    @Override
    public boolean update(AppMenuUpdateRequest request) {
        AppMenu appMenu = new AppMenu();
        BeanUtils.copyProperties(request, appMenu);
        return updateById(appMenu);
    }

	@Override
	public void updateAppRoleMenu(Long roleId, List<Long> appMenuIdList) {
		QueryWrapper<AppRoleMenu> removeWrapper = new QueryWrapper<AppRoleMenu>().eq("role_id", roleId);
		appRoleMenuService.remove(removeWrapper);

		if(CollectionUtils.isNotEmpty(appMenuIdList)){
			List<AppRoleMenu> appRoleMenuList = new ArrayList<>();
			for(Long appMenuId : appMenuIdList){
				AppRoleMenu appRoleMenu = new AppRoleMenu();
				appRoleMenu.setRoleId(roleId);
				appRoleMenu.setMenuId(appMenuId);
				appRoleMenuList.add(appRoleMenu);
			}
			appRoleMenuService.saveBatch(appRoleMenuList);
		}
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String ids) {
	    return deleteLogic(ids);
    }

    @Override
    public AppMenu selectDetail(Long id) {
        AppMenu appMenu = appMenuMapper.selectById(id);
        if(null == appMenu){
	        throw new ServiceException(String.format("%s ID=%s 的记录不存在", this.getClass().getSimpleName(), id));
        }
        return appMenu;
    }

	@Override
	public List<AppMenu> selectMenuList(AppMenuQueryRequest request, Long userId) {
		List<AppMenu> appMenuList;

		if (SysUser.isAdmin(userId)){
			appMenuList = appMenuMapper.selectByCondition(request);
		}else{
			request.setUserId(userId);
			appMenuList = appMenuMapper.selectByCondition(request);
		}
		return appMenuList;
	}

	@Override
	public List<TreeSelect> buildMenuTreeSelect(List<AppMenu> menus) {
		List<AppMenu> menuTrees = buildMenuTree(menus);
		return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
	}

	@Override
	public List<AppMenu> selectMenuTreeByUserId(Long userId) {
		List<AppMenu> menus;
		if (SecurityUtils.isAdmin(userId)){
			AppMenuQueryRequest request = new AppMenuQueryRequest();
			request.setOrderBy("sort");
			request.setIsHide(EBoolean.False.getStringValue());
			menus = selectList(request);
		}
		else{
			menus = appMenuMapper.selectMenuTreeByUserId(userId);
		}
		return getChildPerms(menus, 0);
	}

	@Override
    public List<AppMenu> selectPage(AppMenuQueryRequest request) {
        return appMenuMapper.selectByCondition(request);
    }

    @Override
    public List<AppMenu> selectList(AppMenuQueryRequest request) {
        return appMenuMapper.selectByCondition(request);
    }

	@Override
	public List<AppMenu> selectList(Long userId) {
		AppMenuQueryRequest request = new AppMenuQueryRequest();
		if (!SysUser.isAdmin(userId)){
			request.setUserId(userId);
		}
		return appMenuMapper.selectByCondition(request);
	}

	@Override
	public List<Long> selectMenuListByRoleId(Long roleId) {
		SysRole role = roleMapper.selectRoleById(roleId);
		return appMenuMapper.selectMenuListByRoleId(roleId, role.isAppMenuCheckStrictly());
	}

	@Override
	public List<AppMenu> buildMenuTree(List<AppMenu> menus){
		List<AppMenu> returnList = new ArrayList<>();
		List<Long> tempList = menus.stream().map(AppMenu::getId).collect(Collectors.toList());
		for (Iterator<AppMenu> iterator = menus.iterator(); iterator.hasNext();){
			AppMenu menu = (AppMenu) iterator.next();
			// 如果是顶级节点, 遍历该父节点的所有子节点
			if (!tempList.contains(menu.getParentId())){
				recursionFn(menus, menu);
				returnList.add(menu);
			}
		}
		if (returnList.isEmpty()){
			returnList = menus;
		}
		return returnList;
	}

	private void recursionFn(List<AppMenu> list, AppMenu t){
		// 得到子节点列表
		List<AppMenu> childList = getChildList(list, t);
		t.setChildren(childList);
		for (AppMenu tChild : childList){
			if (hasChild(list, tChild)){
				recursionFn(list, tChild);
			}
		}
	}

	/**
	 * 得到子节点列表
	 */
	private List<AppMenu> getChildList(List<AppMenu> list, AppMenu t){
		List<AppMenu> tlist = new ArrayList<>();
		Iterator<AppMenu> it = list.iterator();
		while (it.hasNext()){
			AppMenu n = (AppMenu) it.next();
			if (n.getParentId().longValue() == t.getId().longValue()){
				tlist.add(n);
			}
		}
		return tlist;
	}

	/**
	 * 判断是否有子节点
	 */
	private boolean hasChild(List<AppMenu> list, AppMenu t){
		return getChildList(list, t).size() > 0;
	}

	/**
	 * 根据父节点的ID获取所有子节点
	 *
	 * @param list 分类表
	 * @param parentId 传入的父节点ID
	 * @return String
	 */
	public List<AppMenu> getChildPerms(List<AppMenu> list, int parentId){
		List<AppMenu> returnList = new ArrayList<>();
		for (Iterator<AppMenu> iterator = list.iterator(); iterator.hasNext();){
			AppMenu t = (AppMenu) iterator.next();
			// 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
			if (t.getParentId() == parentId){
				recursionFn(list, t);
				returnList.add(t);
			}
		}
		return returnList;
	}

}
